import json
import logging
import time
from django.shortcuts import render, redirect
from urllib.parse import urlencode, parse_qs

import requests
from django.http import HttpResponse
from django.shortcuts import render

from django.shortcuts import render, redirect
from fontTools.misc.textTools import tostr

from rest_framework import status
from rest_framework.response import Response
from rest_framework.throttling import AnonRateThrottle

from django.conf import settings
from tools.captcha import cap
from tools.myredis import mredis
from tools.send_sms import sms_service
from tools.verification_code import verification_utils
from user.serializer import SendSMSSerializer, LoginSerializer
from django.http import JsonResponse
from urllib.parse import quote

import requests
from django.http import HttpResponseRedirect
from rest_framework.views import APIView
from rest_framework.response import Response
from urllib.parse import unquote
from user.models import User,ThreeLogin,UserVerify
from user.serializer import UserSerializer,ThreeLoginSerializer
from tools.myjwt import mjwt
# from tools.BaiduTool import bdapi
import asyncio
from django.shortcuts import render
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_http_methods
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework import status
from django.contrib.auth.decorators import login_required
import json
from django.db import models
from .models import User, UserProfile
from .serializer import UserProfileSerializer
from tools.uploadPhoto import q, bucket_name, cdn_domain
import uuid
import time


logger = logging.getLogger(__name__)


# Create your views here.

class ImageCodeView(APIView):
    """
    图片验证码
    """

    def get(self, request):
        captcha_key = request.query_params.get('uuid')
        if not captcha_key:
            return HttpResponse('Missing uuid parameter', status=400)

        try:
            code, buffer = cap.get_captcha()
            mredis.setex(captcha_key, 300, code)

            # 设置正确的响应头
            response = HttpResponse(buffer.getvalue(), content_type='image/png')
            response['Cache-Control'] = 'no-cache, no-store, must-revalidate'
            response['Pragma'] = 'no-cache'
            response['Expires'] = '0'
            response['Access-Control-Allow-Origin'] = '*'
            response['Access-Control-Allow-Methods'] = 'GET, OPTIONS'
            response['Access-Control-Allow-Headers'] = 'Content-Type'

            return response
        except Exception as e:
            logger.error(f"生成验证码失败: {e}")
            return HttpResponse('Failed to generate captcha', status=500)


class SendSMSView(APIView):
    """发送短信接口 - 基于荣联云官方SDK"""

    def post(self, request):
        # 1. 验证数据格式
        serializer = SendSMSSerializer(data=request.data)
        if not serializer.is_valid():
            return Response({
                'success': False,
                'message': '参数验证失败',
                'errors': serializer.errors
            }, status=status.HTTP_400_BAD_REQUEST)

        phone = serializer.validated_data['phone']
        image_code = serializer.validated_data['code']  # 这是图片验证码

        # 2. 验证一分钟内只能发一次
        if verification_utils.check_send_interval(phone):
            return Response({
                'success': False,
                'message': '发送过于频繁，请1分钟后再试'
            }, status=status.HTTP_429_TOO_MANY_REQUESTS)

        # 3. 验证图片验证码（需要从请求中获取uuid）
        uuid = request.data.get('uuid')
        if not uuid:
            return Response({
                'success': False,
                'message': '缺少图片验证码标识'
            }, status=status.HTTP_400_BAD_REQUEST)

        stored_image_code = mredis.get(uuid)
        if not stored_image_code or stored_image_code.upper() != image_code.upper():
            return Response({
                'success': False,
                'message': '图片验证码错误或已过期'
            }, status=status.HTTP_400_BAD_REQUEST)

        # 4. 生成新的短信验证码
        sms_code = verification_utils.generate_verification_code()

        try:
            # 5. 同步调用荣联云发送短信（带重试）
            send_result = sms_service.send_verification_code_with_retry(
                phone,
                sms_code,  # 发送新生成的短信验证码
                settings.SMS_SETTINGS['RETRY_TIMES']
            )

            # 如果返回的是协程对象，则需要await
            import asyncio
            if asyncio.iscoroutine(send_result):
                send_result = asyncio.run(send_result)

            if send_result:
                # 6. 保存短信验证码到Redis
                verification_utils.save_verification_code(phone, sms_code)

                # 7. 设置发送间隔
                verification_utils.set_send_interval(phone)

                # 8. 删除图片验证码（使用后立即清除）
                mredis.delete(uuid)

                return Response({
                    'success': True,
                    'message': '短信发送成功',
                    'data': {
                        'phone': phone,
                        'sent': True,
                        'max_daily': settings.SMS_SETTINGS['MAX_DAILY_SEND']
                    }
                }, status=status.HTTP_200_OK)
            else:
                return Response({
                    'success': False,
                    'message': '短信发送失败，请稍后重试'
                }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

        except Exception as e:
            logger.error(f"短信发送异常: {e}")
            return Response({
                'success': False,
                'message': '系统错误，请稍后重试'
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


class LoginView(APIView):
    """登录接口"""

    def post(self, request):
        # 1. 验证数据格式
        serializer = LoginSerializer(data=request.data)
        if not serializer.is_valid():
            return Response({
                'success': False,
                'message': '参数验证失败',
                'errors': serializer.errors
            }, status=status.HTTP_400_BAD_REQUEST)

        phone = serializer.validated_data['phone']
        sms_code = serializer.validated_data['sms_code']

        try:
            # 2. 验证短信验证码
            stored_code = verification_utils.get_verification_code(phone)
            if not stored_code or stored_code != sms_code:
                return Response({
                    'success': False,
                    'message': '短信验证码错误或已过期'
                }, status=status.HTTP_400_BAD_REQUEST)

            # 3. 验证成功后立即清除验证码
            verification_utils.delete_verification_code(phone)

            # 4. 查询用户是否存在
            try:
                user = User.objects.get(phone=phone)
            except User.DoesNotExist:
                # 如果用户不存在，创建新用户
                user = User.objects.create_user(
                    username=phone,  # 使用手机号作为用户名
                    phone=phone,
                    password=None  # 不设置密码，使用短信验证码登录
                )
                logger.info(f"创建新用户: {phone}")

            # 5. 生成JWT token和refresh token
            payload = {
                'user_id': user.id,
                'phone': user.phone,
                'username': user.username
            }
            token = mjwt.encode(payload)
            retoken = mjwt.encode_refresh_token(payload)

            # 6. 返回token、retoken和userid
            return Response({
                'success': True,
                'message': '登录成功',
                'data': {
                    'token': token,
                    'retoken': retoken,
                    'user_id': user.id,
                    'phone': user.phone,
                    'username': user.username
                }
            }, status=status.HTTP_200_OK)

        except Exception as e:
            logger.error(f"登录异常: {e}")
            return Response({
                'success': False,
                'message': '系统错误，请稍后重试'
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


class LogoutView(APIView):
    """退出登录接口"""
    def post(self, request):
        try:
            # 从请求头获取token
            auth_header = request.headers.get("Authorization")
            if not auth_header:
                return Response({
                    'success': False,
                    'message': '未提供token'
                }, status=status.HTTP_400_BAD_REQUEST)

            # 处理Bearer前缀
            if auth_header.startswith('Bearer '):
                token = auth_header[7:]  # 移除'Bearer '前缀
            else:
                token = auth_header

            # 验证token格式
            if not token:
                return Response({
                    'success': False,
                    'message': 'token格式错误'
                }, status=status.HTTP_400_BAD_REQUEST)

            # 解析token
            try:
                payload = mjwt.decode(token)
                if not payload:
                    return Response({
                        'success': False,
                        'message': 'token无效'
                    }, status=status.HTTP_401_UNAUTHORIZED)
            except Exception as e:
                logger.error(f"token解析失败: {e}")
                return Response({
                    'success': False,
                    'message': 'token无效或已过期'
                }, status=status.HTTP_401_UNAUTHORIZED)

            # 将token加入黑名单（设置24小时过期，与token过期时间一致）
            try:
                exp = int(payload.get('exp', 0)) - int(time.time())
                if exp > 0:
                    mredis.setex(token, exp, 1)  # 设置最后一次登录的token的过期时间
                    print("已经在redis添加退出token")
                else:
                    print("token已过期，无需加入黑名单")
            except Exception as e:
                logger.error(f"Redis操作失败: {e}")
                # 即使Redis操作失败，也允许退出登录

            return Response({
                'success': True,
                'message': '退出登录成功'
            }, status=status.HTTP_200_OK)

        except Exception as e:
            logger.error(f"退出登录异常: {e}")
            return Response({
                'success': False,
                'message': '系统错误，请稍后重试'
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


class RefreshTokenView(APIView):
    """刷新token接口"""

    def post(self, request):
        try:
            # 从请求头获取refresh token
            retoken = request.headers.get("Authorization")
            if not retoken:
                return Response({
                    'success': False,
                    'message': '未提供refresh token'
                }, status=status.HTTP_400_BAD_REQUEST)

            # 解析refresh token
            payload = mjwt.decode_refresh_token(retoken)
            if not payload:
                return Response({
                    'success': False,
                    'message': 'refresh token无效或已过期'
                }, status=status.HTTP_401_UNAUTHORIZED)

            # 检查refresh token是否过期
            if mjwt.is_refresh_token_expired(payload):
                return Response({
                    'success': False,
                    'message': 'refresh token已过期，请重新登录'
                }, status=status.HTTP_401_UNAUTHORIZED)

            # 生成新的token（使用原payload信息，但更新过期时间）
            new_payload = {
                'user_id': payload['user_id'],
                'phone': payload['phone'],
                'username': payload['username']
            }
            new_token = mjwt.encode(new_payload)

            return Response({
                'success': True,
                'message': 'token刷新成功',
                'data': {
                    'token': new_token
                }
            }, status=status.HTTP_200_OK)

        except Exception as e:
            logger.error(f"刷新token异常: {e}")
            return Response({
                'success': False,
                'message': '系统错误，请稍后重试'
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


class UserInfoView(APIView):
    """获取用户信息接口"""
    def get(self, request):
        try:
            # 检查用户是否已登录 - 支持JWT认证
            user = None

            # 方法1: 检查Django默认认证
            if request.user.is_authenticated:
                user = request.user
            else:
                # 方法2: 检查JWT token
                auth_header = request.headers.get('Authorization')
                if auth_header and auth_header.startswith('Bearer '):
                    token = auth_header[7:]  # 移除 'Bearer ' 前缀
                    try:
                        payload = mjwt.decode(token)
                        if payload and 'user_id' in payload:
                            user = User.objects.get(id=payload['user_id'])
                    except Exception as e:
                        logger.error(f"JWT token解析失败: {e}")

            if not user:
                return Response({
                    'success': False,
                    'message': '用户信息获取失败'
                }, status=status.HTTP_401_UNAUTHORIZED)

            return Response({
                'success': True,
                'message': '获取用户信息成功',
                'data': {
                    'user_id': user.id,
                    'phone': user.phone,
                    'username': user.username
                }
            }, status=status.HTTP_200_OK)

        except Exception as e:
            logger.error(f"获取用户信息异常: {e}")
            return Response({
                'success': False,
                'message': '系统错误，请稍后重试'
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

# class DingUrl(APIView):
#     """钉钉授权URL生成接口 - 根据参数返回不同的跳转URL"""
#     已迁移到 factory.py 中的工厂模式实现
#
#     def get(self, request):
#         # 获取登录类型参数
#         login_type = request.GET.get('type', 'dingding')
#
#         logger.info(f"生成授权URL，登录类型: {login_type}")
#
#         if login_type == "dingding":
#             # 钉钉授权URL
#             redirect_uri = 'http://127.0.0.1:8000/user/dingdingCallback/'
#             client_id = 'dingcxkhsbttemu4b4dc'
#
#             # 构建钉钉授权URL
#             auth_url = (
#                 f"https://login.dingtalk.com/oauth2/auth?"
#                 f"redirect_uri={redirect_uri}&"
#                 f"response_type=code&"
#                 f"client_id={client_id}&"
#                 f"scope=openid corpid&"
#                 f"state=dingding&"
#                 f"prompt=consent"
#             )
#
#             return Response({
#                 'success': True,
#                 'message': '获取钉钉授权URL成功',
#                 'data': {
#                     'url': auth_url,
#                     'login_type': login_type
#                 }
#             })
#
#         elif login_type == "wechat":
#             # 微信授权URL（预留）
#             return Response({
#                 'success': True,
#                 'message': '微信登录功能开发中',
#                 'data': {
#                     'url': '',
#                     'login_type': login_type
#                 }
#             })
#
#         elif login_type == "qq":
#             # QQ授权URL（预留）
#             return Response({
#                 'success': True,
#                 'message': 'QQ登录功能开发中',
#                 'data': {
#                     'url': '',
#                     'login_type': login_type
#                 }
#             })
#
#         else:
#             return Response({
#                 'success': False,
#                 'message': f'不支持的登录类型: {login_type}'
#             }, status=400)

# class DingUrl(APIView):
#     def get(self,request):
#         types=request.GET.get('types')
#         if types=="dingding":
#             reul='http://127.0.0.1:8000/user/dingdingCallback/'
#             cid='dingcxkhsbttemu4b4dc'
#             url="https://login.dingtalk.com/oauth2/auth?redirect_uri=%s&response_type=code&client_id=%s&scope=openid corpid&state=dddd&prompt=consent"%(reul,cid)
#             return Response({'code':200,'url':url})
#     def post(self,request):
#         code=request.data['code']
#         types=request.data['types']
#         if types=="dingding":
#             ddur='https://login.dingtalk.com/v1.0/oauth2/userAccessToken'
#             data={
#                 "clientId": "dingcxkhsbttemu4b4dc",
#                 "clientSecret": "OXuv71iocN8gq0O0lILnyJ7WA5WibHumlU2XTpNG3pQJAszD55qNT_LotdJ47GUV",
#                 "code":code,
#                 "refreshToken": 'String',
#                 "grantType": "authorization_code"
#             }
#             mes=requests.post(ddur,data,)
#             token=mes.json()['accessToken']
#             userurl=" https://login.dingtalk.com/v1.0/contact/users/me"
#             users=requests.get(userurl,headers={'x-acs-dingtalk-access-token':token}).json()
#             userid=users['openai']
#             mobile=users['mobile']
#             return Response({'code':200})




class DingTalkStatusCheck(APIView):
    """钉钉应用状态检查"""

    def get(self, request):
        try:
            # 测试钉钉API连接
            test_data = {
                "clientId": "dingcxkhsbttemu4b4dc",
                "clientSecret": "OXuv71iocN8gq0O0lILnyJ7WA5WibHumlU2XTpNG3pQJAszD55qNT_LotdJ47GUV"
            }

            # 尝试连接钉钉API
            test_endpoints = [
                'https://login.dingtalk.com/v1.0/oauth2/userAccessToken',
                'https://api.dingtalk.com/v1.0/oauth2/userAccessToken',
                'https://oapi.dingtalk.com/gettoken'
            ]

            results = {}
            for endpoint in test_endpoints:
                try:
                    resp = requests.post(endpoint, json=test_data, timeout=5)
                    results[endpoint] = {
                        'status_code': resp.status_code,
                        'response_type': 'json' if resp.headers.get('content-type', '').startswith('application/json') else 'html',
                        'response_preview': resp.text[:200] if resp.text else 'empty'
                    }
                except Exception as e:
                    results[endpoint] = {
                        'error': str(e)
                    }

            return Response({
                'success': True,
                'message': '钉钉API连接测试完成',
                'data': {
                    'app_config': {
                        'client_id': 'dingcxkhsbttemu4b4dc',
                        'client_secret': 'OXuv71iocN****LotdJ47GUV'  # 部分隐藏
                    },
                    'api_test_results': results
                }
            })

        except Exception as e:
            return Response({
                'success': False,
                'message': f'状态检查失败: {str(e)}'
            }, status=500)


class DingTalkCallback(APIView):
    """钉钉回调接口 - 处理授权码，获取用户信息，生成JWT令牌"""

    def _check_dingtalk_app_status(self):
        """检查钉钉应用状态"""
        try:
            # 测试钉钉API连接
            test_data = {
                "clientId": "dingcxkhsbttemu4b4dc",
                "clientSecret": "OXuv71iocN8gq0O0lILnyJ7WA5WibHumlU2XTpNG3pQJAszD55qNT_LotdJ47GUV"
            }

            # 尝试连接钉钉API
            resp = requests.post('https://login.dingtalk.com/v1.0/oauth2/userAccessToken',
                               json=test_data, timeout=5)

            return {
                'status_code': resp.status_code,
                'content_type': resp.headers.get('content-type', ''),
                'response_preview': resp.text[:200] if resp.text else 'empty',
                'is_json': 'application/json' in resp.headers.get('content-type', '')
            }

        except Exception as e:
            return {
                'error': str(e)
            }
#
    def get(self, request):
        try:
            # 1. 获取授权码
            authCode = request.query_params.get('code')
            state = request.query_params.get('state', '')

            logger.info(f"收到钉钉回调，授权码: {authCode}, state: {state}")

            if not authCode:
                return Response({
                    'success': False,
                    'message': '授权码缺失'
                }, status=400)

            # 检查钉钉应用状态
            app_status = self._check_dingtalk_app_status()
            logger.info(f"钉钉应用状态检查: {app_status}")

            if 'error' in app_status:
                return Response({
                    'success': False,
                    'message': f'钉钉应用连接失败: {app_status["error"]}'
                }, status=500)

            if not app_status.get('is_json', False):
                return Response({
                    'success': False,
                    'message': f'钉钉应用配置问题，返回非JSON格式: {app_status["response_preview"]}'
                }, status=500)
#
            # 2. 钉钉应用配置
            client_id = "dingcxkhsbttemu4b4dc"
            client_secret = "OXuv71iocN8gq0O0lILnyJ7WA5WibHumlU2XTpNG3pQJAszD55qNT_LotdJ47GUV"

            logger.info(f"钉钉应用配置 - Client ID: {client_id}")

            # 检查是否为测试模式
            if authCode == 'test_code_123456':
                logger.info("使用测试模式")
                # 模拟钉钉用户信息
                name = "测试用户"
                uid = "test_openid_123"
                phone = "13800138000"

                # 处理用户登录逻辑
                tlogin = ThreeLogin.objects.filter(uid=uid, plate='dingding').first()

                if not tlogin:
                    # 创建测试用户
                    user = User.objects.filter(phone=phone).first()
                    if not user:
                        user = User.objects.create(
                            username=phone,
                            phone=phone,
                            first_name=name,
                            is_active=True
                        )

                    # 创建第三方登录记录
                    ThreeLogin.objects.create(
                        user=user,
                        plate='dingding',
                        uid=uid,
                        token='test_token',
                        retoken=''
                    )
                else:
                    user = tlogin.user

                # 生成JWT令牌
                token_data = {
                    'user_id': user.id,
                    'username': user.username,
                    'phone': user.phone,
                    'login_type': 'dingding'
                }
                token = mjwt.encode(token_data)
                refresh_token = mjwt.encode_refresh_token(token_data)

                return Response({
                    'success': True,
                    'message': '钉钉登录成功（测试模式）',
                    'data': {
                        'token': token,
                        'refresh_token': refresh_token,
                        'user_info': {
                            'user_id': user.id,
                            'username': user.username,
                            'nickname': name,
                            'phone': phone,
                            'login_type': 'dingding'
                        },
                        'redirect_url': '/dashboard'
                    }
                })

        except Exception as e:
            logger.error(f"钉钉回调处理异常: {e}")
            return Response({
                'success': False,
                'message': f'系统错误: {str(e)}'
            }, status=500)

#                 # 处理用户登录逻辑
#                 tlogin = ThreeLogin.objects.filter(uid=uid, plate='dingding').first()
#
#                 if not tlogin:
#                     # 创建测试用户
#                     user = User.objects.filter(phone=phone).first()
#                     if not user:
#                         user = User.objects.create(
#                             username=phone,
#                             phone=phone,
#                             first_name=name,
#                             is_active=True
#                         )
#
#                     # 创建第三方登录记录
#                     ThreeLogin.objects.create(
#                         user=user,
#                         plate='dingding',
#                         uid=uid,
#                         token='test_token',
#                         retoken=''
#                     )
#                 else:
#                     user = tlogin.user
#
#                 # 生成JWT令牌
#                 token_data = {
#                     'user_id': user.id,
#                     'username': user.username,
#                     'phone': user.phone,
#                     'login_type': 'dingding'
#                 }
#                 token = mjwt.encode(token_data)
#
#                 return Response({
#                     'success': True,
#                     'message': '钉钉登录成功（测试模式）',
#                     'data': {
#                         'token': token,
#                         'user_info': {
#                             'user_id': user.id,
#                             'username': user.username,
#                             'nickname': name,
#                             'phone': phone
#                         },
#                         'redirect_url': '/dashboard'
#                     }
#                 })
#
#             # 3. 使用requests.get请求钉钉的授权接口，返回token和uid
#             logger.info("开始请求钉钉授权接口获取访问令牌")
#
#             # 构建请求数据
#             token_data = {
#                 "clientId": client_id,
#                 "clientSecret": client_secret,
#                 "code": authCode,
#                 "grantType": "authorization_code"
#             }
#
#             # 请求钉钉授权接口
#             try:
#                 logger.info(f"请求钉钉授权接口，数据: {token_data}")
#                 resp = requests.post('https://login.dingtalk.com/v1.0/oauth2/userAccessToken',
#                                    json=token_data, timeout=10)
#
#                 logger.info(f"钉钉授权接口响应状态码: {resp.status_code}")
#                 logger.info(f"钉钉授权接口响应头: {dict(resp.headers)}")
#                 logger.info(f"钉钉授权接口响应内容: {resp.text}")
#
#                 # 检查响应状态码
#                 if resp.status_code != 200:
#                     return Response({
#                         'success': False,
#                         'message': f'钉钉授权接口请求失败，状态码: {resp.status_code}, 响应: {resp.text}'
#                     }, status=400)
#
#                 # 检查响应内容是否为空
#                 if not resp.text.strip():
#                     return Response({
#                         'success': False,
#                         'message': '钉钉授权接口返回空响应'
#                     }, status=400)
#
#                 # 检查响应内容类型
#                 content_type = resp.headers.get('content-type', '')
#                 if 'application/json' not in content_type and resp.text.strip():
#                     return Response({
#                         'success': False,
#                         'message': f'钉钉授权接口返回非JSON格式: {content_type}, 响应: {resp.text[:200]}'
#                     }, status=400)
#
#                 # 尝试解析JSON
#                 try:
#                     token_result = resp.json()
#                 except ValueError as e:
#                     logger.error(f"JSON解析失败: {e}, 响应内容: {resp.text}")
#                     return Response({
#                         'success': False,
#                         'message': f'钉钉授权接口响应格式错误: {resp.text[:200]}'
#                     }, status=400)
#
#                 # 检查返回的数据结构
#                 if 'accessToken' not in token_result:
#                     logger.error(f"钉钉授权接口返回数据缺少accessToken: {token_result}")
#                     return Response({
#                         'success': False,
#                         'message': f'获取访问令牌失败: {token_result}'
#                     }, status=400)
#
#                 accessToken = token_result.get('accessToken')
#                 logger.info(f"成功获取访问令牌: {accessToken[:10]}...")
#
#             except requests.RequestException as e:
#                 logger.error(f"网络请求异常: {e}")
#                 return Response({
#                     'success': False,
#                     'message': f'网络请求失败: {str(e)}'
#                 }, status=500)
#             except Exception as e:
#                 logger.error(f"请求钉钉授权接口异常: {e}")
#                 return Response({
#                     'success': False,
#                     'message': f'请求钉钉授权接口失败: {str(e)}'
#                 }, status=500)
#
#
#
#             # 4. 用requests.get请求获取钉钉用户信息的接口，携带token，返回手机号
#             logger.info("开始获取钉钉用户信息")
#
#             headers = {"x-acs-dingtalk-access-token": accessToken}
#
#             try:
#                 user_resp = requests.get('https://login.dingtalk.com/v1.0/contact/users/me',
#                                        headers=headers, timeout=10)
#                 logger.info(f"钉钉用户信息接口响应状态码: {user_resp.status_code}")
#                 logger.info(f"钉钉用户信息接口响应内容: {user_resp.text}")
#
#                 if user_resp.status_code != 200:
#                     return Response({
#                         'success': False,
#                         'message': f'获取用户信息失败，状态码: {user_resp.status_code}, 响应: {user_resp.text}'
#                     }, status=400)
#
#                 user_info = user_resp.json()
#
#             except Exception as e:
#                 logger.error(f"请求钉钉用户信息接口异常: {e}")
#                 return Response({
#                     'success': False,
#                     'message': f'请求钉钉用户信息接口失败: {str(e)}'
#                 }, status=500)
#
#             # 提取用户信息
#             name = user_info.get('nick')
#             uid = user_info.get('openId')
#             phone = user_info.get('mobile')
#
#             logger.info(f"钉钉用户信息: name={name}, uid={uid}, phone={phone}")
#
#             # 5. 查询三方登录表根据uid，如果存在获取本平台的用户信息
#             logger.info(f"查询三方登录表，uid: {uid}")
#             tlogin = ThreeLogin.objects.filter(uid=uid, plate='dingding').first()
#
#             if tlogin:
#                 # 如果存在，获取本平台的用户信息，用jwt生成token和retoken，返回给vue，存入localStorage
#                 logger.info(f"三方登录记录存在，用户ID: {tlogin.user.id}")
#                 user = tlogin.user
#
#                 # 更新访问令牌
#                 tlogin.token = accessToken
#                 tlogin.save()
#
#             else:
#                 # 6. 如果不存在，用手机号在用户表中写一份记录，写入三方登录表
#                 logger.info("三方登录记录不存在，开始创建用户记录")
#
#                 if phone:
#                     # 通过手机号查询本地用户是否存在
#                     user = User.objects.filter(phone=phone).first()
#                     if user:
#                         logger.info(f"找到现有用户，绑定钉钉账号: user_id={user.id}, phone={phone}")
#                     else:
#                         # 手机号用户不存在，创建新用户
#                         logger.info(f"手机号用户不存在，创建新用户: phone={phone}")
#                         username = phone
#                         user = User.objects.create(
#                             username=username,
#                             phone=phone,
#                             first_name=name if name else '',
#                             is_active=True
#                         )
#                 else:
#                     # 没有手机号，创建新用户
#                     logger.info("钉钉用户没有手机号，创建新用户")
#                     username = f"ding_{uid}"
#                     user = User.objects.create(
#                         username=username,
#                         phone='',
#                         first_name=name if name else '',
#                         is_active=True
#                     )
#
#                 # 写入三方登录表
#                 logger.info(f"创建第三方登录记录: user_id={user.id}, uid={uid}")
#                 ThreeLogin.objects.create(
#                     user=user,
#                     plate='dingding',
#                     uid=uid,
#                     token=accessToken,
#                     retoken=''  # 钉钉可能没有refresh_token
#                 )
#
#             # 7. 用jwt生成token和retoken，返回给vue，存入localStorage
#             logger.info(f"生成JWT令牌，用户ID: {user.id}")
#
#             # 生成访问令牌
#             token_data = {
#                 'user_id': user.id,
#                 'username': user.username,
#                 'phone': user.phone,
#                 'login_type': 'dingding'
#             }
#             token = mjwt.encode(token_data)
#
#             # 生成刷新令牌
#             refresh_token_data = {
#                 'user_id': user.id,
#                 'username': user.username,
#                 'phone': user.phone,
#                 'login_type': 'dingding',
#                 'type': 'refresh'
#             }
#             refresh_token = mjwt.encode_refresh_token(refresh_token_data)
#
#             # 返回成功响应，供Vue存入localStorage
#             return Response({
#                 'success': True,
#                 'message': '钉钉登录成功',
#                 'data': {
#                     'token': token,
#                     'refresh_token': refresh_token,
#                     'user_info': {
#                         'user_id': user.id,
#                         'username': user.username,
#                         'nickname': name,
#                         'phone': phone,
#                         'login_type': 'dingding'
#                     },
#                     'redirect_url': '/dashboard'
#                 }
#             })
#
#         except requests.RequestException as e:
#             return Response({
#                 'success': False,
#                 'message': f'网络请求失败: {str(e)}'
#             }, status=500)
#         except Exception as e:
#             return Response({
#                 'success': False,
#                 'message': f'系统错误: {str(e)}'
#             }, status=500)




# 微博请求授权接口
# class WeiBoAuthView(APIView):
#     def get(self,request):
#         types = request.query_params.get('type')
#         if types == 'weibo':
#             client_id = "3674019597"
#             redirect_uri = "https://localhost:5173/weibo/callback"  # 回调地址 返回code 空白页面
#             url = f"https://api.weibo.com/oauth2/authorize?client_id={client_id}&response_type=code&redirect_uri={redirect_uri}"
#             return Response({"code": 200, "url": url})   # url是微博授权页面的地址,跳入里面获取code并点击ok
#             # 正确的请求会在浏览器内打开一个授权确认页面，当用户同意授权后，会重定向到授权回调地址，并带上回传的数据
#
#
# # 微博登录接口：get获取token，post获取手机号
# class WeiBoLoginView(APIView):
#     # 用code换区用户的token
#     # 微博授权接口获取到code后，请求微博的token接口，获取到用户的token，再用token换取用户的手机号
#     # 微博的token接口地址：https://api.weibo.com/oauth2/access_token
#     def get(self,request):
#         # 接收code
#         code = request.query_params.get('code')
#         if not code:
#             return Response({
#                 'code':400,
#                 'message':'code不存在,回调失败'
#             })
#         client_id = "3674019597"
#         client_secret = "b1d5d9d5d5"
#         redirect_uri = "https://localhost:5173/weibo/callback"  # 回调地址
#         grant_type = "authorization_code"
#         data = {
#             'client_id': client_id,
#             'client_secret': client_secret,
#             'grant_type': grant_type,
#             'code': code,
#             'redirect_uri': redirect_uri
#         }
#         weibo_url = 'https://api.weibo.com/oauth2/access_token'
#         res = requests.post(weibo_url,data=data)
#         resdata = res.text
#         json_res = json.loads(resdata)
#         access_token = json_res["access_token"]   # 想获取用户信息，需要用access_token去获取用户信息，耶斯
#         uid = json_res["uid"]
#
#         # 微博登录成功后，获取用户的手机号的用户信息借口：https://api.weibo.com/2/users/show.json?access_token=ACCESS_TOKEN&uid=UID
#
#
#         # 表中查询是否登录过
#         three_login = ThreeLogin.objects.filter(uid=uid,token=access_token,plate='weibo').first()
#         if three_login :
#             user = three_login.user   # 获取用户id
#             # 更新第三方的token（如果需要）
#             three_login.token = access_token
#             user.save()
#
#             # 构建payload-User表字段
#             payload = {
#                 'user_id': user.id,
#                 'username': user.username,
#                 'phone': user.phone,
#                 'email': user.email if user.email else '',
#                 'login_type': 'weibo',
#                 'plate': 'weibo',
#                 'weibo_uid': uid
#             }
#             # 生成JWT token
#             payload = mjwt.encode(payload)
#             # 重定向到前端登录页面
#             return redirect(settings.FRONTEND_URL + '?token=' + payload)
#
#
#     # 生成token接口
#     # def post(self, request):



# Gitee平台登录授权接口
# class GiteeAuthView(APIView):
#     def get(self,request):
#         types = request.query_params.get('type')
#         if types == 'gitee':
#             client_id = settings.GITEE_CLIENT_ID
#             # 尝试多种可能的回调地址格式
#             # 如果Gitee应用配置中设置的是其他格式，请修改这里
#             # 请根据您的Gitee应用配置选择正确的格式：
#
#             # 格式1: localhost + 无斜杠 (与Gitee应用配置一致)
#             redirect_uri = "http://localhost:8000/api/gitee_callback"
#             url = f'https://gitee.com/oauth/authorize?client_id={client_id}&redirect_uri={redirect_uri}&' \
#                   f'response_type=code&scope=user_info'
#
#             logger.info(f"Gitee登录URL生成: {url}")
#
#             return Response({
#                 'code':200,
#                 "message":"gitee登录url生成成功",
#                 "data":{
#                     "url":url
#                 }
#             })   # url是gitee授权页面的地址,跳入里面获取code并点击ok
#             # 正确的请求会在浏览器内打开一个授权确认页面，当用户同意授权后，会重定向到授权回调地址，并带上回传的数据


# Gitee回调接口
# class GiteeCallBackView(APIView):
#     def get(self,request):
          # 获取到的code
#         code = request.query_params.get('code')
#         logger.info(f"Gitee回调接收到code: {code}")
#
#         if not code:
#             logger.error("Gitee回调失败: code不存在")
#             return Response({
#                 'code':400,
#                 'message':'code不存在,回调失败'
#             })
#
#         try:
#             # 通过code获取token
#             token_url = 'https://gitee.com/oauth/token'
#             # token?grant_type=authorization_code&code={code}&client_id={client_id}&redirect_uri={redirect_uri}&client_secret={client_secret}
#             token_data = {
#                 'grant_type': 'authorization_code',  # 添加必需的grant_type参数
#                 'code': code,
#                 'client_id': settings.GITEE_CLIENT_ID,
#                 'redirect_uri': "http://localhost:3000/gitee-callback",
#                 'client_secret': settings.GITEE_CLIENT_SECRET
#             }  # 参数
#
#             logger.info(f"请求Gitee token，参数: {token_data}")
#             res = requests.post(token_url,data=token_data)
#             logger.info(f"Gitee token响应状态码: {res.status_code}")
#             logger.info(f"Gitee token响应内容: {res.text}")
#
#             res_data = res.json()
#             logger.info(f"Gitee token响应数据: {res_data}")
#
#             # 检查是否有错误信息
#             if 'error' in res_data:
#                 error_msg = res_data.get('error_description', res_data.get('error', '未知错误'))
#                 logger.error(f"Gitee token获取错误: {error_msg}")
#                 return Response({
#                     'code': 400,
#                     'message': f'Gitee授权失败: {error_msg}'
#                 })
#
#             access_token = res_data.get('access_token')
#             print("access_token:", access_token)
#             if not access_token:
#                 logger.error(f"Gitee token获取失败: {res_data}")
#                 return Response({
#                     'code': 400,
#                     'message': 'Gitee授权失败，请重新登录'
#                 })
#
#             # 获取用户信息  token换用户信息
#             user_url = 'https://gitee.com/api/v5/user'
#             headers = {
#                 'Authorization':f'Bearer {access_token}'
#             }
#
#             logger.info(f"请求Gitee用户信息，URL: {user_url}")
#             user_res = requests.get(user_url,headers=headers)
#             logger.info(f"Gitee用户信息响应状态码: {user_res.status_code}")
#             logger.info(f"Gitee用户信息响应内容: {user_res.text}")
#
#             user_info = user_res.json()
#
#             gitee_id = user_info.get('id')
#             username = user_info.get('name')
#             email = user_info.get('email')
#
#             if not gitee_id or not username:
#                 logger.error(f"Gitee用户信息获取失败: {user_info}")
#                 return Response({
#                     'code': 400,
#                     'message': 'Gitee用户信息获取失败，请重新登录'
#                 })
#
#             # 第三方表中查询用户信息
#             three_info = ThreeLogin.objects.filter(uid=gitee_id,plate='gitee').first()
#             if three_info:   # 存在的话生成登录token
#                 user = three_info.user   # 获取用户对象
#                 # 更新token
#                 three_info.token = access_token
#                 three_info.save()
#             else:   # 反之 没找到 没有登录记录 没有注册 就创建用户
#                 # 如果email为空，设置为空字符串
#                 email = email or ''
#                 user = User.objects.create(username=username, email=email)
#                 ThreeLogin.objects.create(uid=gitee_id, plate='gitee', token=access_token, user=user)
#                 user.save()
#
#             # 创建payload jwt token，生成登录token返回给前端
#             payload = {
#                 "user_id": user.id,
#                 "phone": user.phone or "",
#                 "username": user.username
#             }
#             jwt_token = mjwt.encode(payload)
#             refresh_token = mjwt.encode_refresh_token(payload)
#
#             # 重定向到前端页面，携带token和用户信息
#             frontend_url = "http://localhost:3000/gitee-callback"
#             query_params = [
#                 f"token={jwt_token}",
#                 f"re_token={refresh_token}",
#                 f"user_id={user.id}",
#                 f"username={quote(user.username)}",
#                 f"email={quote(user.email or '')}"
#             ]
#             return HttpResponseRedirect(f'{frontend_url}?{"&".join(query_params)}')
#
#         except Exception as e:
#             logger.error(f"Gitee绑定异常: {e}")
#             # 如果是code过期，给出更明确的提示
#             if "invalid_grant" in str(e) or "code" in str(e).lower():
#                 return Response({
#                     'code': 400,
#                     'message': '授权码已过期，请重新登录'
#                 })
#             return Response({
#                 'code': 500,
#                 'message': 'gitee绑定失败，请重试'
#             })

class WeChatLogin(APIView):
    def get(self, request):
        # 微信开放平台应用的 AppID
        app_id = "你的微信开放平台 AppID"
        # 授权成功后重定向的回调地址，需在微信开放平台配置
        redirect_uri = quote("http://localhost:3000/wechat-callback")  # 开发环境
        # redirect_uri = quote("https://yourdomain.com/wechat-callback")  # 生产环境
        params = [
            f"appid={app_id}",
            f"redirect_uri={redirect_uri}",
            "response_type=code",
            "scope=snsapi_login",
            "state=STATE"
        ]
        url = "https://open.weixin.qq.com/connect/qrconnect?" + "&".join(params) + "#wechat_redirect"
        return JsonResponse({"url": url})


class WeChatCallback(APIView):
    def get(self, request):
        # 从回调参数中获取code和state
        code = request.query_params.get('code')
        state = request.query_params.get('state')

        # 验证state，防止CSRF攻击（实际应用中应与请求时的state对比）
        if not state:
            return Response({"code": 10001, "msg": "state参数缺失"})

        # 1. 使用code获取access_token和openid
        app_id = "你的微信开放平台AppID"
        app_secret = "你的微信开放平台AppSecret"
        token_url = "https://api.weixin.qq.com/sns/oauth2/access_token"

        params = {
            "appid": app_id,
            "secret": app_secret,
            "code": code,
            "grant_type": "authorization_code"
        }

        # 调用微信接口获取access_token
        resp = requests.get(token_url, params=params).json()

        # 检查是否获取成功
        if "errcode" in resp:
            return Response({
                "code": 10002,
                "msg": f"获取access_token失败: {resp.get('errmsg', '未知错误')}"
            })

        access_token = resp.get('access_token')
        openid = resp.get('openid')
        unionid = resp.get('unionid', '')  # 可选，多个应用间唯一

        # 2. 使用access_token和openid获取用户信息
        user_info_url = "https://api.weixin.qq.com/sns/userinfo"
        user_params = {
            "access_token": access_token,
            "openid": openid,
            "lang": "zh_CN"
        }

        user_resp = requests.get(user_info_url, params=user_params).json()

        # 检查用户信息获取是否成功
        if "errcode" in user_resp:
            return Response({
                "code": 10003,
                "msg": f"获取用户信息失败: {user_resp.get('errmsg', '未知错误')}"
            })

        # 提取用户信息
        nickname = user_resp.get('nickname')
        headimgurl = user_resp.get('headimgurl')  # 头像URL
        # 微信用户信息中手机号需要单独获取，这里先留空
        phone = ""

        # 3. 处理用户登录逻辑（类似钉钉回调的处理方式）
        # 查找是否已有该微信用户的登录记录（plate="微信"表示微信登录，与钉钉区分）
        sfl = ThreeLogin.objects.filter(uid=openid, plate="微信").first()

        if not sfl:
            # 新用户处理：检查是否有绑定的手机号用户
            user = None
            if phone:  # 如果有手机号（实际需通过单独接口获取）
                user = User.objects.filter(phone=phone).first()

            # 如果没有找到用户，则创建新用户
            if not user:
                userinfo = {
                    "name": nickname,
                    "phone": phone,
                    "password": openid[:8],  # 临时密码，实际应更安全
                    "username": f"wx_{openid[:10]}"  # 生成唯一用户名
                }
                us = UserSerializer(data=userinfo)
                if us.is_valid():
                    user = us.save()
                else:
                    return Response({"code": 10004, "msg": tostr(us.errors)})

            # 写入三方登录表
            sfinfo = {
                "types": 2,  # 2表示微信登录
                "token": access_token,
                "uid": openid,
                "userid": user.id,
                "extra": {"unionid": unionid, "avatar": headimgurl}  # 额外信息
            }
            sfs = ThreeLoginSerializer(data=sfinfo)
            if sfs.is_valid():
                sfs.save()
            else:
                return Response({"code": 10005, "msg": tostr(sfs.errors)})
        else:
            # 老用户更新token
            user = sfl.userid
            sfl.token = access_token
            sfl.save()

        # 4. 生成JWT令牌并跳转回前端
        payload = {
            "userid": user.id,
            "username": user.username,
            "exp": int(time.time()) + 60 * 60 * 2  # 2小时有效期
        }
        token = mjwt.encode(payload)

        # 生成刷新令牌
        payload["exp"] = int(time.time()) + 60 * 60 * 24 * 2  # 2天有效期
        refresh_token = mjwt.encode(payload)

        # 跳转回前端登录页面并携带参数
        query_params = [
            f"userid={user.id}",
            f"username={user.username}",
            f"token={token}",
            f"refreshToken={refresh_token}"
        ]
        return HttpResponseRedirect(f'http://localhost:8080/#/login?{"&".join(query_params)}')



#获取QQ登录的URL
class QQLogin(APIView):
    def get(self, request):
        qq_auth_url = "https://graph.qq.com/oauth2.0/authorize"
        params = {
            "response_type": "code",
            "client_id": settings.QQ_APP_ID,
            "redirect_uri": settings.QQ_REDIRECT_URI,
            "state": "your_random_state_string",  # 用于防止CSRF攻击
            "scope": "get_user_info",  # 申请的权限范围
        }
        url = f"{qq_auth_url}?{urlencode(params)}"
        return Response({"url": url})

#QQ登录的回调
class QQCallback(APIView):
    def get(self, request):
        """处理QQ回调"""
        code = request.GET.get('code')
        # state = request.GET.get('state')

        if not code:
            return Response({
                'success': False,
                'message': '授权失败'
            }, status=status.HTTP_400_BAD_REQUEST)

        # 使用code获取access_token
        token_url = "https://graph.qq.com/oauth2.0/token"
        token_params = {
            "grant_type": "authorization_code",
            "client_id": settings.QQ_APP_ID,
            "client_secret": settings.QQ_APP_KEY,
            "code": code,
            "redirect_uri": settings.QQ_REDIRECT_URI,
        }

        token_response = requests.get(token_url, params=token_params)
        # QQ返回的是字符串格式: access_token=YOUR_ACCESS_TOKEN&expires_in=7776000&refresh_token=YOUR_REFRESH_TOKEN
        token_data = parse_qs(token_response.text)
        access_token = token_data.get('access_token', [None])[0]

        if not access_token:
            return Response({
                'success': False,
                'message': '获取access_token失败'
            }, status=status.HTTP_400_BAD_REQUEST)

        # 使用access_token获取openid
        openid_url = "https://graph.qq.com/oauth2.0/me"
        openid_response = requests.get(openid_url, params={"access_token": access_token})
        # 返回格式: callback( {"client_id":"YOUR_APPID","openid":"YOUR_OPENID"} );
        openid_data = json.loads(openid_response.text[10:-3])  # 去除callback包装
        openid = openid_data.get('openid')

        if not openid:
            return Response({
                'success': False,
                'message': '获取openid失败'
            }, status=status.HTTP_400_BAD_REQUEST)

        # 使用access_token和openid获取用户信息
        user_info_url = "https://graph.qq.com/user/get_user_info"
        user_info_params = {
            "access_token": access_token,
            "oauth_consumer_key": settings.QQ_APP_ID,
            "openid": openid,
        }
        user_info_response = requests.get(user_info_url, params=user_info_params)
        user_info = user_info_response.json()

        # 处理用户信息
        try:
            # 1. 查询ThreeLogin表是否有该openid的用户
            three_login = ThreeLogin.objects.filter(uid=openid, plate='QQ').first()

            if three_login:
                # 2. 如果存在，获取关联的本平台用户
                user = three_login.user

                # 3. 生成JWT token和refresh token
                payload = {
                    'user_id': user.id,
                    'phone': user.phone,
                    'username': user.username
                }
                token = mjwt.encode(payload)
                retoken = mjwt.encode_refresh_token(payload)

                # 4. 返回token、retoken和用户信息
                return Response({
                    'success': True,
                    'message': '登录成功',
                    'data': {
                        'token': token,
                        'retoken': retoken,
                        'user_id': user.id,
                        'phone': user.phone,
                        'username': user.username
                    }
                }, status=status.HTTP_200_OK)
            else:
                # 5. 如果不存在，返回特殊状态码，前端跳转手机号登录页面
                return Response({
                    'success': False,
                    'message': '用户未绑定',
                    'code': 'USER_NOT_BOUND',
                    'data': {
                        'openid': openid,
                        'user_info': user_info
                    }
                }, status=status.HTTP_400_BAD_REQUEST)

        except Exception as e:
            logger.error(f"QQ登录处理异常: {e}")
            return Response({
                'success': False,
                'message': '系统错误，请稍后重试'
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


class BindPhoneView(APIView):
    """绑定手机号接口"""

    def post(self, request):
        # 1. 验证数据格式
        openid = request.data.get('openid')
        phone = request.data.get('phone')
        sms_code = request.data.get('sms_code')

        if not all([openid, phone, sms_code]):
            return Response({
                'success': False,
                'message': '参数不完整'
            }, status=status.HTTP_400_BAD_REQUEST)

        try:
            # 2. 验证短信验证码
            stored_code = verification_utils.get_verification_code(phone)
            if not stored_code or stored_code != sms_code:
                return Response({
                    'success': False,
                    'message': '短信验证码错误或已过期'
                }, status=status.HTTP_400_BAD_REQUEST)

            # 3. 验证成功后立即清除验证码
            verification_utils.delete_verification_code(phone)

            # 4. 查询用户是否存在
            try:
                user = User.objects.get(phone=phone)
            except User.DoesNotExist:
                # 如果用户不存在，创建新用户
                user = User.objects.create_user(
                    username=phone,  # 使用手机号作为用户名
                    phone=phone,
                    password=None  # 不设置密码，使用短信验证码登录
                )
                logger.info(f"创建新用户: {phone}")

            # 5. 创建或更新第三方登录记录
            three_login, created = ThreeLogin.objects.update_or_create(
                uid=openid,
                plate='QQ',
                defaults={'user': user}
            )

            # 6. 生成JWT token和refresh token
            payload = {
                'user_id': user.id,
                'phone': user.phone,
                'username': user.username
            }
            token = mjwt.encode(payload)
            retoken = mjwt.encode_refresh_token(payload)

            # 7. 返回token、retoken和用户信息
            return Response({
                'success': True,
                'message': '绑定成功',
                'data': {
                    'token': token,
                    'retoken': retoken,
                    'user_id': user.id,
                    'phone': user.phone,
                    'username': user.username
                }
            }, status=status.HTTP_200_OK)

        except Exception as e:
            logger.error(f"绑定手机号异常: {e}")
            return Response({
                'success': False,
                'message': '系统错误，请稍后重试'
            })


@api_view(['GET'])
def getUserProfile(request):
    """
    获取用户资料
    """
    try:
        # 从自定义中间件获取用户信息
        user_info = getattr(request, 'user_info', None)
        if not user_info:
            return Response({
                'success': False,
                'message': '未登录或登录已过期'
            }, status=status.HTTP_401_UNAUTHORIZED)

        user_id = user_info.get('user_id')
        print(f"[getUserProfile] 用户ID: {user_id}")
        
        user = User.objects.get(id=user_id)
        profile, created = UserProfile.objects.get_or_create(user=user)
        
        print(f"[getUserProfile] 用户资料创建状态: {created}")
        print(f"[getUserProfile] 身高字段: {profile.height}, 类型: {type(profile.height)}")
        print(f"[getUserProfile] 体重字段: {profile.weight}, 类型: {type(profile.weight)}")

        serializer = UserProfileSerializer(profile)
        response_data = {
            'success': True,
            'data': serializer.data
        }
        
        print(f"[getUserProfile] 返回数据: {response_data}")
        return Response(response_data)
    except Exception as e:
        print(f"[getUserProfile] 发生异常: {str(e)}")
        import traceback
        print(f"[getUserProfile] 异常堆栈: {traceback.format_exc()}")
        return Response({
            'success': False,
            'message': f'获取用户资料失败: {str(e)}'
        }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

@api_view(['POST'])
def updateUserProfile(request):
    """
    更新用户资料
    """
    try:
        # 从自定义中间件获取用户信息
        user_info = getattr(request, 'user_info', None)
        if not user_info:
            return Response({
                'success': False,
                'message': '未登录或登录已过期'
            }, status=status.HTTP_401_UNAUTHORIZED)

        user_id = user_info.get('user_id')
        user = User.objects.get(id=user_id)
        profile, created = UserProfile.objects.get_or_create(user=user)

        data = request.data

        # 更新基本信息
        if 'nickname' in data:
            profile.nickname = data['nickname']
        if 'avatar' in data:
            profile.avatar = data['avatar']
        if 'gender' in data:
            profile.gender = data['gender']
        if 'birth_date' in data:
            profile.birth_date = data['birth_date']

        # 更新身体指标
        if 'height' in data:
            profile.height = data['height']
        if 'weight' in data:
            profile.weight = data['weight']

        # 更新健身目标
        if 'fitness_goal' in data:
            profile.fitness_goal = data['fitness_goal']
        if 'fitness_level' in data:
            profile.fitness_level = data['fitness_level']
        if 'activity_level' in data:
            profile.activity_level = data['activity_level']

        # 更新饮食偏好
        if 'dietary_preference' in data:
            profile.dietary_preference = data['dietary_preference']
        if 'food_allergies' in data:
            profile.food_allergies = data['food_allergies']
        if 'dietary_restrictions' in data:
            profile.dietary_restrictions = data['dietary_restrictions']

        # 更新健身偏好
        if 'preferred_workout_duration' in data:
            profile.preferred_workout_duration = data['preferred_workout_duration']
        if 'preferred_workout_times' in data:
            profile.preferred_workout_times = data['preferred_workout_times']

        # 更新健康信息
        if 'has_diabetes' in data:
            profile.has_diabetes = data['has_diabetes']
        if 'has_hypertension' in data:
            profile.has_hypertension = data['has_hypertension']
        if 'has_heart_disease' in data:
            profile.has_heart_disease = data['has_heart_disease']

        profile.save()

        serializer = UserProfileSerializer(profile)
        return Response({
            'success': True,
            'message': '用户资料更新成功',
            'data': serializer.data
        })
    except Exception as e:
        return Response({
            'success': False,
            'message': f'更新用户资料失败: {str(e)}'
        }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

@api_view(['GET'])
def getQiniuToken(request):
    """
    获取七牛云上传token
    """
    try:
        # 从自定义中间件获取用户信息
        user_info = getattr(request, 'user_info', None)
        if not user_info:
            return Response({
                'success': False,
                'message': '未登录或登录已过期'
            }, status=status.HTTP_401_UNAUTHORIZED)
        # 生成唯一的文件名
        file_key = f"avatar/{uuid.uuid4().hex}_{int(time.time())}"

        # 生成上传token，有效期7天
        token = q.upload_token(bucket_name, file_key, 3600*24*7)

        return Response({
            'success': True,
            'data': {
                'token': token,
                'key': file_key,
                'domain': cdn_domain,
                'download_url': f"{cdn_domain}/{file_key}"  # 基础URL，前端需要生成下载token
            }
        })
    except Exception as e:
        return Response({
            'success': False,
            'message': f'获取上传token失败: {str(e)}'
        }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

@api_view(['GET'])
def getQiniuDownloadToken(request):
    """
    获取七牛云下载token（用于私有空间文件访问）
    """
    try:
        # 从自定义中间件获取用户信息
        user_info = getattr(request, 'user_info', None)
        if not user_info:
            return Response({
                'success': False,
                'message': '未登录或登录已过期'
            }, status=status.HTTP_401_UNAUTHORIZED)

        # 获取文件key
        file_key = request.query_params.get('key')
        print(f"[getQiniuDownloadToken] 原始key: {file_key}")
        
        if not file_key:
            return Response({
                'success': False,
                'message': '缺少文件key参数'
            }, status=status.HTTP_400_BAD_REQUEST)

        # 清理key，去掉可能包含的URL参数
        if '?' in file_key:
            file_key = file_key.split('?')[0]
        
        print(f"[getQiniuDownloadToken] 清理后的key: {file_key}")

        # 生成下载token，有效期1小时
        download_url = f"{cdn_domain}/{file_key}"
        print(f"[getQiniuDownloadToken] 下载URL: {download_url}")
        
        download_token_url = q.private_download_url(download_url, expires=3600)
        print(f"[getQiniuDownloadToken] 生成的下载token URL: {download_token_url}")

        response_data = {
            'success': True,
            'data': {
                'download_url': download_token_url
            }
        }
        
        print(f"[getQiniuDownloadToken] 返回数据: {response_data}")
        return Response(response_data)
    except Exception as e:
        print(f"[getQiniuDownloadToken] 发生异常: {str(e)}")
        import traceback
        print(f"[getQiniuDownloadToken] 异常堆栈: {traceback.format_exc()}")
        return Response({
            'success': False,
            'message': f'获取下载token失败: {str(e)}'
        }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

@api_view(['GET', 'PUT'])
def getUserProfileDetail(request, profile_id):
    """
    获取指定用户的资料详情，支持GET和PUT方法
    """
    try:
        # 从自定义中间件获取用户信息
        user_info = getattr(request, 'user_info', None)
        if not user_info:
            return Response({
                'success': False,
                'message': '未登录或登录已过期'
            }, status=status.HTTP_401_UNAUTHORIZED)

        # 检查用户是否存在
        try:
            user = User.objects.get(id=profile_id)
        except User.DoesNotExist:
            return Response({
                'success': False,
                'message': '用户不存在'
            }, status=status.HTTP_404_NOT_FOUND)

        # 获取或创建用户资料
        profile, created = UserProfile.objects.get_or_create(user=user)

        if request.method == 'GET':
            # GET方法：返回用户资料
            serializer = UserProfileSerializer(profile)
            return Response({
                'success': True,
                'data': serializer.data
            })
        
        elif request.method == 'PUT':
            # PUT方法：更新用户资料
            data = request.data
            
            # 更新基本信息
            if 'nickname' in data:
                profile.nickname = data['nickname']
            if 'avatar' in data:
                profile.avatar = data['avatar']
            if 'gender' in data:
                profile.gender = data['gender']
            if 'birth_date' in data:
                profile.birth_date = data['birth_date']

            # 更新身体指标
            if 'height' in data:
                profile.height = data['height']
            if 'weight' in data:
                profile.weight = data['weight']

            # 更新健身目标
            if 'fitness_goal' in data:
                profile.fitness_goal = data['fitness_goal']
            if 'fitness_level' in data:
                profile.fitness_level = data['fitness_level']
            if 'activity_level' in data:
                profile.activity_level = data['activity_level']

            # 更新饮食偏好
            if 'dietary_preference' in data:
                profile.dietary_preference = data['dietary_preference']
            if 'food_allergies' in data:
                profile.food_allergies = data['food_allergies']
            if 'dietary_restrictions' in data:
                profile.dietary_restrictions = data['dietary_restrictions']

            # 更新健身偏好
            if 'preferred_workout_duration' in data:
                profile.preferred_workout_duration = data['preferred_workout_duration']
            if 'preferred_workout_times' in data:
                profile.preferred_workout_times = data['preferred_workout_times']

            # 更新健康信息
            if 'has_diabetes' in data:
                profile.has_diabetes = data['has_diabetes']
            if 'has_hypertension' in data:
                profile.has_hypertension = data['has_hypertension']
            if 'has_heart_disease' in data:
                profile.has_heart_disease = data['has_heart_disease']

            profile.save()

            serializer = UserProfileSerializer(profile)
            return Response({
                'success': True,
                'message': '用户资料更新成功',
                'data': serializer.data
            })

    except Exception as e:
        print(f"[用户资料详情] 发生异常: {str(e)}")
        import traceback
        print(f"[用户资料详情] 异常堆栈: {traceback.format_exc()}")
        return Response({
            'success': False,
            'message': f'操作失败: {str(e)}'
        }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

